#include "kov.h"

int main(int argc, char *argv[])
{
    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
    
    try {
        DataStructure* data = loadDataSet(argv[1]);
        data->printSummary(std::cout);
		std::ofstream fc(argv[2]);
		clock_t start = clock();
		unsigned int* counter = new unsigned int(0);
		Kov(data,&fc,atoi(argv[3]), counter, strcmp(argv[4],"c")==0);
		clock_t end = clock();
		std::cout<<"\nTime:"<<(end-start)/1000;
		std::cout<<"\nSets:"<<*counter<<"\n";
		fc << "\n" << (end-start)/1000<<"\nSets:"<<*counter;
		delete counter;
		fc.close();
        delete data;
    }
    catch (std::exception e) {
        e.what();
    }

    _CrtDumpMemoryLeaks();
    system("PAUSE");
    return 0;
}

void Kov(DataStructure *ds, std::ofstream *fc, unsigned int minSup,unsigned int* counter, bool asChar, bool (*sort_f)(const OAPair &e1, const OAPair &e2)){
	if(ds->getAllObjects()->data.size() >= minSup){
		OAPair oa = std::make_pair( new ObjectSet(*(ds->getAllObjects())), new AttributeSet());
		FormalContext *tmpFC = new FormalContext();
		for (std::set<Attribute>::const_iterator i = ds->getAllAtributes()->data.begin(); i != ds->getAllAtributes()->data.end(); i++){
			if(ds->getObjects(*i)->data.size() >=minSup){
				oa.second->data.insert(Attribute(*i));
				OAPair tmpPair = std::make_pair( new ObjectSet(*( ds->getObjects(*i) ))  , new AttributeSet());
				tmpPair.second->data.insert(Attribute(*i));
				tmpFC->data.push_back(tmpPair);
			}
		}
		FormalContext* localP = LocalContext(oa, tmpFC);
		for (std::vector<OAPair>::iterator i = tmpFC->data.begin(); i != tmpFC->data.end(); i++) {
			delete i->first;
			delete i->second;
		}
		delete tmpFC;
		ClosureForEmptySet(*(ds->getAllAtributes()),oa,*localP);
		SaveOA(fc,oa, asChar);
		++(*counter);
		AttributeSet* processedSets = new AttributeSet();
		KovExtend(ds->getAllAtributes(), *localP, minSup, fc, processedSets,counter,asChar);
		delete processedSets;
		for (std::vector<OAPair>::iterator i = localP->data.begin(); i != localP->data.end(); i++) {
			delete i->first;
			delete i->second;
		}
		delete localP;
		delete oa.first;
		delete oa.second;
	}
}

void PrintOA(OAPair &oa){
	ObjectSet *O = oa.first;
	AttributeSet *A = oa.second;
	std::cout<< "\nO:{ ";
	for (std::set<Object>::const_iterator i = O->data.begin(); i != O->data.end(); i++){
		std::cout<< *i << " ";
	}
	std::cout << "}, A:{ ";
	for (std::set<Attribute>::const_iterator i = A->data.begin(); i != A->data.end(); i++){
		std::cout<< *i << " ";
	}
	std::cout<< "}";
}

void SaveOA(std::ofstream *fc, OAPair &oa, bool asChar){
	//PrintOA(oa);
	ObjectSet *O = oa.first;
	AttributeSet *A = oa.second;
	(*fc) << "<{";
	for (std::set<Object>::const_iterator i = O->data.begin(); i != O->data.end(); i++)
			(*fc) << *i << " ";
	(*fc) << "}>, <{";
	for (std::set<Attribute>::const_iterator i = A->data.begin(); i != A->data.end(); i++)
		if(asChar){
			char c = 'a' -1 + (*i);
			(*fc) << c;
		}
		else
			(*fc) << *i << " ";
	(*fc) << "}>\n";
}

bool AttributeSetProcessed(const AttributeSet& set, const AttributeSet* sets){
	for(std::set<Attribute>::const_iterator attr = set.data.begin(); attr != set.data.end(); ++attr)
		for(std::set<Attribute>::const_iterator attr2 = sets->data.begin(); attr2 != sets->data.end(); ++attr2)
			if(*attr == *attr2)
				return true;
	return false;
}

void KovExtend(AttributeSet *allAttributes, FormalContext &p, unsigned int minSup, std::ofstream *fc, AttributeSet *processedSets,unsigned int* counter, bool asChar, bool (*sort_f)(const OAPair &e1, const OAPair &e2)){
	Order(p);
	for (unsigned int i = 0; i < p.data.size(); i++){
		OAPair pair = std::make_pair(new ObjectSet(*(p.data.at(i).first)), new AttributeSet(*p.data.at(i).second));
		if(!AttributeSetProcessed(*(p.data.at(i).second), processedSets)){
			DeltaClosure deltaClosure = ClosureDelta(p.data.at(i), &p);
			
			bool processed = false;
			for (DeltaClosure::const_iterator d = deltaClosure.begin(); d != deltaClosure.end(); d++){
				if(AttributeSetProcessed((*d), processedSets)){
					processed = true;
					break;
				}
			}
			
			if(processed){
				for(std::set<Attribute>::const_iterator attr = p.data.at(i).second->data.begin(); attr != p.data.at(i).second->data.end(); ++attr)
					processedSets->data.insert(Attribute(*attr));
			}else{
				
				FormalContext* localP = LocalContextMinSup(pair, deltaClosure, &p, minSup);
				Order(*localP);
				Closure(*allAttributes, pair, *localP);
				
				for(std::set<Attribute>::const_iterator attr = p.data.at(i).second->data.begin(); attr != p.data.at(i).second->data.end(); ++attr)
					processedSets->data.insert(Attribute(*attr));
				SaveOA(fc,pair, asChar);
				++(*counter);
				AttributeSet* sets = new AttributeSet(*processedSets);
				KovExtend(allAttributes, *localP, minSup, fc, sets, counter,asChar);
				delete sets;
				
				for (std::vector<OAPair>::iterator i = localP->data.begin(); i != localP->data.end(); i++) {
					delete i->first;
					delete i->second;
				}
				delete localP;
			}
		}
		delete pair.first;
		delete pair.second;
	}
}

DeltaClosure ClosureDelta(const OAPair &oa, const FormalContext *p){
	std::vector<OAPair> deltaClosure;
	bool copy = false;
	for(std::vector<OAPair>::const_iterator i = p->data.begin(); i!=p->data.end(); i++){
		if(copy == false && i->first == oa.first && i->second == oa.second)
			copy = true;
		if(copy == true){
			OAPair pair = std::make_pair(i->first, i->second);
			deltaClosure.push_back(pair);
		}
	}
	for(std::set<Object>::const_iterator o = oa.first->data.begin(); o != oa.first->data.end(); o++){
		for(std::vector<OAPair>::const_iterator i = deltaClosure.begin(); i != deltaClosure.end();){
			bool containsObject = false;
			for(std::set<Object>::const_iterator oi = i->first->data.begin(); oi != i->first->data.end(); ++oi){
				if(*oi == *o){
					containsObject = true;
					break;
				}
			}
			if(containsObject == false){
				i = deltaClosure.erase(i);
			}
			else
				++i;
		}	
	}
	DeltaClosure result;
	for(std::vector<OAPair>::const_iterator i = deltaClosure.begin(); i != deltaClosure.end();++i){
		AttributeSet set = AttributeSet(*(i->second)); 	
		result.push_back(set);
	}
	return result;
}
